package main

import "fmt"

// ==========继承==========
// 1、如果一个结构体嵌套了另一个匿名结构体, 那么这个结构体就可以直接访问匿名结构体的字段和方法(不管首字母是大写还是小写), 从而实现了继承
// 2、匿名结构体字段访问可以简化
// 3、当结构体和匿名结构体有相同的字段或方法时, 编译器采用就近原则访问, 如果希望访问匿名结构体的字段和方法, 可以通过匿名结构体名来区分
// 4、结构体嵌入两个或多个匿名结构体, 如果两个匿名结构体有相同的字段和方法(同时结构体本身没有同名的字段和方法),
// 在访问时, 就必须明确指定匿名结构体名字, 否则编译器报错
// 5、嵌套匿名结构体后, 也可以在创建结构体变量时, 直接指定各个匿名结构体字段的值
// 6、如果一个结构体嵌套了一个有名结构体, 这种模式就是组合, 如果是组合关系, 那么在访问组合的结构体的字段或方法时, 必须带上结构体的名字
// 7、结构体也可以嵌入基本数据类型

type Person struct {
	Name string
	age  int
}

type Student struct {
	Name string
	age  int // 字段小写, 在同一个package里创建的变量可以访问该字段, 在别的包创建的Student变量不能访问该字段
}

func (s *Student) GetName() string {
	return s.Name
}

func (s *Student) getAge() int {
	return s.age
}

type Jason struct {
	Student // 嵌套了一个Student匿名结构体
}

type Jonathan struct {
	Student        // 嵌套了一个Student匿名结构体结构体
	Name    string //
	age     int
}

type Kitty struct {
	Person  // 嵌套了一个Person匿名结构体
	Student // 嵌套了一个Student匿名结构体
}

type Maxwell struct {
	Person
	Student
	Name string
	age  int
}

type Allen struct {
	P Person // 嵌套一个Person有名结构体
}

type Alex struct {
	P    Person
	Name string
	age  int
}

type Base struct {
	Person
	int // 基本数据类型作为匿名字段int
}

func main() {
	// 1、Jason结构体嵌套(继承)了Student结构体, 则Jason结构体变量可以直接访问Student结构体的所有字段和方法
	var jason Jason
	fmt.Println(jason.Student.Name, jason.Student.age) // "" 0
	fmt.Println(jason.Name, jason.age)                 // "" 0
	jason.Student.Name = "jason"                       // 也可以简化写成jason.Name = "jason"
	jason.Student.age = 18                             // 也可以简化写成jason.age = 18
	jason.Student.GetName()                            // 也可以简化写成jason.GetName()
	jason.Student.getAge()                             // 也可以简化写成jason.getAge()
	fmt.Println(jason.Student.Name, jason.Student.age) // jason 18
	fmt.Println(jason.Name, jason.age)                 // jason 18

	var jasonClone Jason
	jasonClone.Name = "jasonClone"
	jasonClone.age = 19
	fmt.Println(jasonClone.Student.Name, jasonClone.Student.age) // jasonClone 19
	fmt.Println(jasonClone.Name, jasonClone.age)                 // jasonClone 19

	// 2、Jonathan结构体嵌套(继承)了Student结构体, 且Jonathan结构体跟Student结构体有相同的字段
	// 编译器采用就近原则先找子类的字段, 若要访问父类字段和方法, 可以通过: 子类变量.父类.字段、子类变量.父类.方法
	var jonathan Jonathan
	jonathan.Name = "jonathon"
	jonathan.age = 20
	fmt.Println(jonathan.Name, jonathan.age)                 // jonathon 20
	fmt.Println(jonathan.Student.Name, jonathan.Student.age) // "" 0
	jonathan.Student.Name = "jonathon~"
	jonathan.Student.age = 21
	fmt.Println(jonathan.Name, jonathan.age)                 // jonathon 20
	fmt.Println(jonathan.Student.Name, jonathan.Student.age) // jonathon~ 21

	var jonathanClone Jonathan
	jonathanClone.Student.Name = "jonathanClone~"
	jonathanClone.Student.age = 22
	fmt.Println(jonathanClone.Name, jonathanClone.age)                 // "" 0
	fmt.Println(jonathanClone.Student.Name, jonathanClone.Student.age) // jonathanClone~ 22
	jonathanClone.Name = "jonathanClone"
	jonathanClone.age = 23
	fmt.Println(jonathanClone.Name, jonathanClone.age)                 // jonathanClone 23
	fmt.Println(jonathanClone.Student.Name, jonathanClone.Student.age) // jonathanClone~ 22

	// 3、Kitty结构体嵌套了Person、Student结构体, Person、Student结构体有相同的字段, 并且Kitty结构体没有与他们相同的字段
	// 如果要访问必须指定嵌套结构体的名字
	// 不能直接访问kitty.Name、kitty.age
	kitty := Kitty{}
	kitty.Person.Name = "kittyPerson"
	kitty.Person.age = 9
	kitty.Student.Name = "kittyStudent"
	kitty.Student.age = 10
	fmt.Println(kitty.Person.Name, kitty.Person.age)   // // kittyPerson 9
	fmt.Println(kitty.Student.Name, kitty.Student.age) // kittyStudent 10

	// 4、Maxwell结构体嵌套了Person、Student结构体, Person、Student结构体有相同的字段, 并且Maxwell结构体与他们有相同的字段
	// 编译器采用就近原则先找子类的字段, 若要访问父类字段和方法, 可以通过: 子类变量.父类.字段、子类变量.父类.方法
	maxwell := Maxwell{}
	maxwell.Name = "maxwell"
	maxwell.age = 28
	fmt.Println(maxwell.Name, maxwell.age)                 // maxwell 28
	fmt.Println(maxwell.Person.Name, maxwell.Person.age)   // "" 0
	fmt.Println(maxwell.Student.Name, maxwell.Student.age) // "" 0

	maxwell.Person.Name = "maxwellPerson"
	maxwell.Person.age = 29
	fmt.Println(maxwell.Name, maxwell.age)                 // maxwell 28
	fmt.Println(maxwell.Person.Name, maxwell.Person.age)   // maxwellPerson 29
	fmt.Println(maxwell.Student.Name, maxwell.Student.age) // "" 0

	maxwell.Student.Name = "maxwellStudent"
	maxwell.Student.age = 30
	fmt.Println(maxwell.Name, maxwell.age)                 // maxwell 28
	fmt.Println(maxwell.Person.Name, maxwell.Person.age)   // maxwellPerson 29
	fmt.Println(maxwell.Student.Name, maxwell.Student.age) // maxwellStudent 30

	// 5、嵌套匿名结构体后, 也可以在创建结构体变量时, 直接指定各个匿名结构体字段的值
	max := Maxwell{Person: Person{"pMax", 100}, Student: Student{"sMax", 200}}
	fmt.Println(max.Name, max.age) // "" 0

	// 6、Allen结构体嵌套了有名结构体Person, 如果Allen结构体本身没有Name和age字段, 那么给Allen结构体变量赋值和获取都要指定有名结构体
	var allen Allen
	allen.P.Name = "allen"
	allen.P.age = 36
	fmt.Println(allen.P.Name, allen.P.age) // allen 36    不能fmt.Println(allen.Name, allen.age)

	alex := Alex{}
	alex.Name = "alex"
	alex.age = 40
	fmt.Println(alex.Name, alex.age)     // "alex" 40
	fmt.Println(alex.P.Name, alex.P.age) // "" 0

	// 7、嵌入匿名基本数据类型
	base := Base{}
	base.int = 1
	fmt.Println(base.int) // 1

}
